package com.founder.devwork.persistence.gateway.gitlab;

import com.founder.devwork.persistence.gateway.gitlab.datasource.GitDataSource;
import com.founder.devwork.persistence.gateway.gitlab.dto.CommitDTO;
import com.founder.devwork.persistence.gateway.gitlab.dto.CommitPkDTO;
import com.founder.devwork.persistence.gateway.gitlab.dto.RepoDTO;
import com.founder.devwork.persistence.gateway.gitlab.dto.UserDTO;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;

/**
 * GitGatewayImpl 用于实现 Git 网关接口。
 * 提供获取仓库、用户、分支、提交等方法。
 */
@Component
public class GitGatewayImpl implements GitGateway {

    private GitDataSource dataSource;
    private WebClient gitClient;

    /**
     * 构造函数。
     * @param dataSource Git 数据源
     */
    public GitGatewayImpl(GitDataSource dataSource) {
        this.dataSource = dataSource;
        buildClient();
    }

    /**
     * 构建 Git 客户端。
     */
    private void buildClient() {
        this.gitClient = WebClient.builder()
            .baseUrl(dataSource.getBaseUrl())
            .defaultHeader("PRIVATE-TOKEN", dataSource.getToken())
            .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
            .build();
    }

    /**
     * 设置 Git 数据源。
     * @param dataSource Git 数据源
     */
    @Override
    public void setDataSource(GitDataSource dataSource) {
        this.dataSource = dataSource;
        buildClient();
    }

    /**
     * 根据仓库 ID 获取仓库信息。
     * @param repoId 仓库 ID
     * @return 仓库信息
     */
    @Override
    public RepoDTO getRepoById(Long repoId) {
        return gitClient.get().uri("/projects/" + repoId).retrieve().bodyToMono(RepoDTO.class).block();
    }

    /**
     * 获取所有用户。
     * @param page 页码
     * @param perPage 每页条数
     * @return 用户列表
     */
    @Override
    public List<UserDTO> getAllUsers(int page, int perPage) {
        return gitClient
            .get()
            .uri(uriBuilder -> uriBuilder.path("/users").queryParam("page", page).queryParam("per_page", perPage).build())
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<List<UserDTO>>() {})
            .block();
    }

    /**
     * 根据用户 ID 获取用户信息。
     * @param userId 用户 ID
     * @return 用户信息
     */
    @Override
    public UserDTO getUserById(Long userId) {
        return gitClient.get().uri("/users/" + userId).retrieve().bodyToMono(UserDTO.class).block();
    }

    /**
     * 获取仓库的分支列表。
     * @param repoId 仓库 ID
     * @return 分支列表
     */
    @Override
    public List<String> getBranches(Long repoId) {
        try {
            return gitClient
                .get()
                .uri("/projects/{repoId}/repository/branches", repoId)
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<List<Map<String, Object>>>() {})
                .map(list ->
                    list
                        .stream()
                        .map(m -> (String) m.get("name"))
                        .filter(name -> name != null)
                        .collect(java.util.stream.Collectors.toList())
                )
                .block();
        } catch (WebClientResponseException e) {
            if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
                return new ArrayList<>();
            }
            throw e;
        }
    }

    /**
     * 获取所有仓库。
     * @param page 页码
     * @param perPage 每页条数
     * @return 仓库列表
     */
    @Override
    public List<RepoDTO> getAllRepos(int page, int perPage) {
        return gitClient
            .get()
            .uri(uriBuilder -> uriBuilder.path("/projects").queryParam("page", page).queryParam("per_page", perPage).queryParam("simple", true).build())
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<List<RepoDTO>>() {})
            .block();
    }

    /**
     * 获取仓库的提交信息。
     * @param repoId 仓库 ID
     * @param branch 分支
     * @param sinceDate 开始日期
     * @param untilDate 结束日期
     * @param page 页码
     * @param perPage 每页条数
     * @return 提交信息
     */
    @Override
    public Set<CommitPkDTO> getCommitsPk(Long repoId, String branch, String sinceDate, String untilDate, int page, int perPage) {
        try {
            Set<CommitPkDTO> result = gitClient
                .get()
                .uri(uriBuilder ->
                    uriBuilder
                        .path("/projects/" + repoId + "/repository/commits")
                        .queryParam("ref_name", branch)
                        .queryParam("since", sinceDate)
                        .queryParam("until", untilDate)
                        .queryParam("page", page)
                        .queryParam("per_page", perPage)
                        .build()
                )
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<HashSet<CommitPkDTO>>() {})
                .block();
            result.forEach(commit -> commit.setRepoId(repoId));
            return result;
        } catch (WebClientResponseException e) {
            if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
                return new HashSet<>();
            }
            throw e;
        }
    }

    /**
     * 根据主键获取提交信息。
     * @param pk 提交主键
     * @return 提交信息
     */
    @Override
    public CommitDTO getCommitByPk(CommitPkDTO pk) {
        CommitDTO result = gitClient.get().uri("/projects/{repoId}/repository/commits/{sha}", pk.getRepoId(), pk.getSha()).retrieve().bodyToMono(CommitDTO.class).block();
        result.setRepoId(pk.getRepoId());
        return result;
    }
}
